/*
 * SummaryOfTheDay.java
 *
 * Created on June 27, 2007, 10:31 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package com.semanticvoid.lifelogger.metrics.browse;

import com.semanticvoid.lifelogger.db.DbInterface;
import com.semanticvoid.lifelogger.entity.BrowseHistoryEntity;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.TimeZone;
import java.util.Vector;

/**
 *
 * @author anand_kishore
 */
public class SummaryOfTheDay {
    
    /** The date of the day for which the summary is to be generated */
    String date;
           
    /** Creates a new instance of SummaryOfTheDay */
    public SummaryOfTheDay(String date) {
        this.date = date;
    }
    
    public LinkedHashSet<BrowseHistoryEntity> summarize() {
        LinkedHashSet<BrowseHistoryEntity> interestingItems = new LinkedHashSet<BrowseHistoryEntity>();
        
        if(date.equals("")) {
            return interestingItems;
        }
        
        ArrayList<ProbabilityEntity> list = calculateProbabilities();
        
        for(ProbabilityEntity pEntity : list) {
            BrowseHistoryEntity bEntity = pEntity.getBEntity();
            
            if(pEntity.getProbability() > 0.5) {
                interestingItems.add(bEntity);
            }
            
            System.out.println(pEntity.getProbability() + "  :  " + bEntity.getTitle());
        }
        
        return interestingItems;
    }
    
    private ArrayList<ProbabilityEntity> calculateProbabilities() {
        ArrayList<ProbabilityEntity> inverseProbabilitySet = new ArrayList<ProbabilityEntity>();
        Vector<BrowseHistoryEntity> entitiesForLast7Days = entitiesForLast7Days();
        Vector<BrowseHistoryEntity> entitiesForGivenDay = entitiesForGivenDay();
        
        int number_of_entitiesForLast7Days = 0;
        int number_of_entitiesForGivenDay = 0;
        
        if(entitiesForGivenDay.size() == 0 || entitiesForLast7Days.size() == 0) {
            System.out.println("No summary");
        } else {
            number_of_entitiesForGivenDay = entitiesForGivenDay.size();
            number_of_entitiesForLast7Days = entitiesForLast7Days.size();
            
            // Populate list of similar docs from the last 7 days dataset
            HashMap<BrowseHistoryEntity, Vector<BrowseHistoryEntity>> given_last_similarity_map = populateSimilarDocs(entitiesForGivenDay, entitiesForLast7Days);
            
            // Populate list of similar docs from the given days dataset
            HashMap<BrowseHistoryEntity, Vector<BrowseHistoryEntity>> given_given_similarity_map = populateSimilarDocs(entitiesForGivenDay, entitiesForGivenDay);
            
            // Calculate probabilities for each entity in set for given day
            for(BrowseHistoryEntity bEntity : entitiesForGivenDay) {
                double probability = ((double) given_given_similarity_map.get(bEntity).size() / (double) number_of_entitiesForGivenDay) * ((double) given_last_similarity_map.get(bEntity).size() / (double) number_of_entitiesForLast7Days);
                
                ProbabilityEntity pEntity = new ProbabilityEntity(bEntity, 1-probability);
                
                inverseProbabilitySet.add(pEntity);
            }
            
            Collections.sort(inverseProbabilitySet, new DescendingProbabilitiesComparator());
        }
        
        return inverseProbabilitySet;
    }
    
    private Vector<BrowseHistoryEntity> entitiesForLast7Days() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        Date jDate;
        
        try {
            jDate = dateFormat.parse(date);
        } catch(ParseException pe) {
            pe.printStackTrace();
            return null;
        }
        
        cal.setTime(jDate);
        // Incrementing date and month due to crappy Java date which starts at 0 rather than 1
        cal.add(cal.DATE, 1);
        cal.add(cal.MONTH, 1);
        
        String toDate;
        String fromDate;
               
        cal.add(cal.DATE, -1);
        toDate = cal.get(cal.YEAR) + "-" + cal.get(cal.MONTH) + "-" + cal.get(cal.DATE);
        
        cal.add(cal.DATE, -7);
        fromDate = cal.get(cal.YEAR) + "-" + cal.get(cal.MONTH) + "-" + cal.get(cal.DATE);
        
        Vector<BrowseHistoryEntity> entites = DbInterface.getBrowseHistoryEntitiesForDateRange(fromDate, toDate);
        
        return entites;
    }
    
    private Vector<BrowseHistoryEntity> entitiesForGivenDay() {
        Vector<BrowseHistoryEntity> entites = DbInterface.getBrowseHistoryEntitiesForDateRange(date, date);
        
        return entites;
    }

    private HashMap<BrowseHistoryEntity, Vector<BrowseHistoryEntity>> populateSimilarDocs(Vector<BrowseHistoryEntity> set1, Vector<BrowseHistoryEntity> set2) {
        HashMap<BrowseHistoryEntity, Vector<BrowseHistoryEntity>> similarityMap = new HashMap<BrowseHistoryEntity, Vector<BrowseHistoryEntity>>();
        
        for(BrowseHistoryEntity b_set1 : set1) {
            Vector<BrowseHistoryEntity> similarEntities = new Vector<BrowseHistoryEntity>();
            
            for(BrowseHistoryEntity b_set2 : set2) {
                // If the entities are same continue
                if(b_set1 == b_set2) {
                    continue;
                } else {
                    double similarity = b_set1.cosineSimilarity(b_set2);
                    
                    if(similarity > 0.9d) {
                        similarEntities.add(b_set2);
                    }
                }
            }
            
            similarityMap.put(b_set1, similarEntities);
        }
        
        return similarityMap;
    }
    
    class ProbabilityEntity {
        private BrowseHistoryEntity bEntity;
        private double probability;
        
        public ProbabilityEntity(BrowseHistoryEntity bEntity, double probability) {
            this.bEntity = bEntity;
            this.probability = probability;
        }

        public double getProbability() {
            return probability;
        }

        public void setProbability(double probability) {
            this.probability = probability;
        }

        public BrowseHistoryEntity getBEntity() {
            return bEntity;
        }

        public void setBEntity(BrowseHistoryEntity bEntity) {
            this.bEntity = bEntity;
        }
    }
    
    class DescendingProbabilitiesComparator implements Comparator {
        public int compare(Object o1, Object o2) {
            ProbabilityEntity p1 = (ProbabilityEntity) o1;
            ProbabilityEntity p2 = (ProbabilityEntity) o2;
            
            if(p1.getProbability() > p2.getProbability()) {
                return -1;
            } else if(p1.getProbability() < p2.getProbability()) {
                return +1;
            } else {
                return 0;
            }
        }
    }
}
